iT邦幫忙

2023 iThome 鐵人賽

DAY 29
0

學習原因:

Flaky Test 為不穩定測試,指的是同一個測試案例在不同的執行中可能會產生不同的結果,有時通過,有時失敗。這會大幅降低測試的可靠性。因此解決 Flaky Test 是自動化測試中的一個重要課題,需要針對不同的問題作出審查,以及優化。

學習目標:

  • 了解 Flaky Test 的成因
  • 思考如何避免 Flaky Test 的發生
  • 學習應用 monkeypatchunittest.mockpytest-rerunfailures 等套件。

Flaky Test 可能是由於以下因素導致的:

  1. 測試環境變化: Test Case 可能對測試環境中的變化影響,包括硬體、軟體、網路等。最常見的就是網路不穩了。
  2. 競爭條件: 當 Test Case 依賴於並行執行或資源共享時,可能會產生競爭條件,導致測試結果不一致。(I.e. 同時修改相同的資源)
  3. 順序相依性: Test Case 的執行順序可能會影響其結果,導致測試不穩定。
  4. 外部資源: Test Case 可能涉及外部資源,如 API 請求,可能會受到外部資源狀態的影響。
  5. 隨機性: 如果測試案例包含隨機性元素,則其結果可能在每次執行時都有所不同。

而解決 Flaky Test 的方法可能包括:

  • 適當的等待策略: 如果測試中涉及到異步操作或等待某些條件滿足,確保使用適當的等待策略,避免過長或過短的等待時間。
  1. 隔離測試環境: 測試環境的變化可能導致測試結果不穩定。確保你在測試運行時使用一個穩定且一致的測試環境,避免外部干擾。例如應用 Docker 建一個獨立環境作測試。

  2. 避免競爭條件: 確保在測試案例中使用適當的資源分配,避免競爭條件的產生。如應用不同的 Test Data。

  3. 隔離外部依賴: 如果測試案例涉及外部服務、資料庫等依賴,考慮使用模擬服務或偽造物件來隔離這些依賴,以確保測試的穩定性。

    monkeypatchpytest 內建的一個 fixture,用於模擬和修改運行環境。它允許你在測試中修改 Python 程序的內部操作,例如修改函數的行為、設定環境變數、模擬外部依賴等。
    以下例子是模擬 api response,通常應用在需要第三方串接的 API 來作測試時,避免外部的依賴,會寫一個 Mock Service 來取代。也可以是用模擬實際情況下難以重現的情況,例如服務器錯誤、網絡中斷等。

    import requests
    import pytest
    from unittest.mock import Mock
    
    def get_data_from_service():
        response = requests.get("https://example.com/api/data")
        return response.json()
    
    def test_get_data_from_service(monkeypatch):
        # 創建模擬的回應
        mock_response = Mock()
        mock_response.json.return_value = {"key": "result"}
    
        # 模擬 requests.get
        mock_get = Mock(return_value=mock_response)
        monkeypatch.setattr("requests.get", mock_get)
    
        # 執行測試
        response = requests.get("https://example.com/api/data").json()
    
        # 斷言結果
        assert response == {"key": "result"}
    
        # 使用 monkeypatch.undo() 還原修改
        monkeypatch.undo()
    
  4. 避免時間相關問題: 測試中的時間相關行為可能導致不穩定的結果。如果測試需要模擬時間,可以使用測試框架提供的時間模擬工具。可應用 unittest.mock 套件的 patch 來模擬。

    from unittest.mock import patch
    import time
    
    def test_my_function_with_mock_time():
        # 模擬 time.time() 返回固定值
        with patch("time.time", return_value=1234567890.0):
            result = time.time()
            assert result == 1234567890.0
    
  5. 測試數據管理: 使用固定的、可控的測試數據,確保測試案例的執行結果可重複且一致。

  6. 建立重跑機制: 讓失敗的 Test Case 自動重跑以確認產品自身是否存在問題。

    可使用 pytest-rerunfailures 套件,使自動重跑 Failed 的 Test Case。安裝套件後,在執行時加入參數 --reruns 決定最多的 Rerun 次數。

    pip install pytest-rerunfailures
    
    # 失敗的 Test Case 最多 Rerun 5 次,都失敗才算 Test Case Failed. 
    pytest --rerun 5
    

    Rerun 成功,Test Case 的狀態則會轉成 Passed。在 Allure Report 會看到 Status 為 Passed,但會多了一個炸彈圖案在 Test Case 以標示此為 Flaky Test,打開 History 可以看到每次的執行狀況,從而審查不穩定狀況發生的原因。

    https://ithelp.ithome.com.tw/upload/images/20231004/20162038nx2sVt6sfa.png

  7. 修復問題根本原因: 如果你能夠確定 Flaky Test 的根本原因,儘可能修復問題,而不僅僅是處理測試失敗。

Flaky Test 的成因眾多,都需要透過觀察,發現問題,再選用適當的策略去避免。以上只是提供常見問題的解決方法,剩下的交給你思考囉。


上一篇
Day 28: Parallel Testing
下一篇
Day 30: 導入自動化測試建議
系列文
從 0 開始培育成為自動化測試工程師的學習指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言